package cuatroenraya.jugadores;

import cuatroenraya.Jugador;

public class JugadorAlumnoG3 extends Jugador {
    int[][] susPuntos;      //almacena el puntaje del oponente para calcular el prox movimiento
    int[][] misPuntos;      //almacena mi puntaje para calcular el prox movimiento
    int[] casillero;        //almacena la fila y columna del nuevo movimiento
    int priorizar=0;        //0=debe recorrer el tablero para ver si hay fichas puestas
                            //1=el tablero fue recorrido y existe una pieza del oponente
                            //2=el tablero fue recorrido y no existe una ficha del oponente

    public JugadorAlumnoG3(){}

    public int[] jugar(int[][] tablero)
    {
        //inicializo variables
        casillero = new int[2];
        misPuntos = new int[8][8];
        susPuntos = new int[8][8];
        
/**
 * Verifico si el primer movimiento lo realizo yo o mi oponente. Si lo realizo yo entonces priorizo el
 * algoritmo para que en caso de presentarse pesos iguales en ofensiva y defensiva, la decision debe 
 * ser atacar. En caso de que juegue primiero mi oponente, tendre que optar por defenderme hasta encontrar
 * una situacion favorable.
 */
    if(priorizar==0){
        verificarElementoTablero(tablero);  //verifica si hay elementos en el tablero y de quien son
    }
 /**
 * para comenzar asignamos la primer ficha en el centro del tablero, fila 4 colum 4. En el caso
 * que empiece a jugar el oponente, se asgina el valor de la izquierda
 */
        if(tablero[3][3] == 0){
            casillero[0] = 3;
            casillero[1] = 3;
            return casillero;
        }else{
            if(tablero[3][3]!=1){
                if(tablero[3][2]==0){
                    casillero[0] = 3;
                    casillero[1] = 2;
                    return casillero;
                }
            }
        }

/**
 * De aca en adelante lo que se hace es analizar el tablero y establecer un puntaje en base a las fichas
 * que tenemos ubicadas nosotros y las que tiene ubicada el adversario. Este puntaje permitira determinar
 * si el prox movimiento es ataque o defensa.
 */
        //analizo puntajes para ofensiva, es decir mis movimientos realizados
        for (int i=0; i<8; i++){
            for (int j=0; j<8; j++){
                if (tablero[i][j]==0){     //busco un casillero vacio y analizo los vecinos
                
/**
 * Lo que hago es analizar la cantidad de fichas que tengo puestas en forma sucesivas en las distintas
 * direcciones. De esta manera, si tengo 3 fichas juntas alineadas a mi espacio vacio, entonces mi puntaje
 * es -1 (muy alto supuestamente), por lo tanto pongo una ficha mas en ese espacio Y GANO :-)
 */
                    //analizo en forma vertical vertical
                    int ptoV=obtenerPuntajeVertical(1, i, j, tablero);
                    if (ptoV==-1){
                        casillero[0]=i;
                        casillero[1]=j;
                        return casillero;   //GANE
                    }
                    misPuntos[i][j]+=ptoV;  //si no pude ganar entonces sumo puntos en ese lugar
                    
                    //analizo en forma horizontal
                    int ptoH=obtenerPuntajeHoriz(1, i, j, tablero);
                    if (ptoH==-1){
                        casillero[0]=i;
                        casillero[1]=j;
                        return casillero;   //GANE
                    }
                    misPuntos[i][j]+=ptoH;                

                    //analizo en forma diagonal con pendiente positiva
                    int ptoDP=puntajeDiagonalPositiva(1, i, j, tablero);
                    if (ptoDP==-1){
                        casillero[0]=i;
                        casillero[1]=j;
                        return casillero;   //GANE
                    }
                    misPuntos[i][j]+=ptoDP;

                    //analizo en forma diagonal con pendiente negativa
                    int ptoDN=puntajeDiagonalNegativa(1, i, j, tablero);
                    if (ptoDN==-1){
                        casillero[0]=i;
                        casillero[1]=j;
                        return casillero;   //GANE
                    }
                    misPuntos[i][j]+=ptoDN;                                          
                }
            }
        }

/**
 * se utiliza la misma metodologia que antes pero ahora se analiza el puntaje del adversario para determinar
 * si tengo que defenderme. Si tengo tres fichas del oponente alieneadas entonces tapo
 */
        for (int i=0; i<8; i++){
            for (int j=0; j<8; j++){
                if (tablero[i][j]==0){
                    int ptoV=obtenerPuntajeVertical(2, i, j, tablero);
                    if (ptoV==-1){
                        casillero[0]=i;
                        casillero[1]=j;
                        return casillero;   //tape
                    }
                    susPuntos[i][j]+=ptoV;  //si no tape la opcion ganadora entonces sumo puntos p' la prox

                    int ptoH=obtenerPuntajeHoriz(2, i, j, tablero);
                    if (ptoH==-1){
                        casillero[0]=i;
                        casillero[1]=j;
                        return casillero;      //tape
                    }
                    susPuntos[i][j]+=ptoH;

                    int ptoDP=puntajeDiagonalPositiva(2, i, j, tablero);
                    if (ptoDP==-1){
                        casillero[0]=i;
                        casillero[1]=j;
                        return casillero;       //tape
                    }
                    susPuntos[i][j]+=ptoDP;

                    int ptoDN=puntajeDiagonalNegativa(2, i, j, tablero);
                    if (ptoDN==-1){
                        casillero[0]=i;
                        casillero[1]=j;
                        return casillero;       //tape
                    }
                    susPuntos[i][j]+=ptoDN;
                }
            }
        }
        return this.calcularProxMovimiento();//calcula el proximo movimiento
    }

/**
 * Verifica las fichas de la siguiente manera:       /                       *
 *                                                  /                       /
 *                                     ascendente: /         descendente:  /
 *                                                /                       /
 *                                               *                       /
 * @param jug: numero del jugador
 * @param f: fila que se analiza
 * @param c: columna que se analiza
 * @param t: tablero
 * @return puntaje correspondiente a tal asignacion
 */
    private int puntajeDiagonalPositiva(int jug, int f, int c, int[][] t){
        int cont = 0;   //cuenta las puntos
        int b1=0, b2=0;    //se utilizan para finalizar la busqueda en un sentido si no
                           //encontramos un elemento adyacente al punto estudiado

        for (int i=1; i<4; i++){
            if ((f-i)>-1 && (c+i)<8 && b1==0){  //ascendente
                if (t[(f-i)][(c+i)]==jug)   cont++;
                else    b1=1;
            }
            if((f+i)<8 && (c-i)>-1 && b2==0){   //descendente
                if (t[(f+i)][(c-i)]==jug)  cont++;
                else b2=1;
            }
        }
        return obtenerPuntaje(cont);
    }
    
/**
 *                          \                         *
 *             Ascendente:   \           Descendente:  \
 *                            \                         \
 *                             *                         \
 */
    private int puntajeDiagonalNegativa(int jug, int f, int c, int[][] t)
    {
        int cont = 0;
        int b1=0, b2=0;

        for (int i=1; i<4; i++){
            if ((f-i)>-1 && (c-i)>-1 && b1==0){     //Ascendente
                if (t[(f-i)][(c-i)]==jug)   cont++;
                else    b1=1;
            }
            if((f+i)<8 && (c+i)<8 && b2==0){        //Descendente
                if (t[(f+i)][(c+i)]==jug)  cont++;
                else b2=1;
            }
        }
        return obtenerPuntaje(cont);
    }

/**
 *          Izquiera: ----------*                   Derecha:   *----------
 */
    private int obtenerPuntajeHoriz(int jug, int f, int c, int[][] t)
    {
        int cont = 0;
        int b1=0, b2=0;

        for (int i=1; i<4; i++){    //izquiera
            if ((c-i)>-1 && b1==0){
                if (t[f][(c-i)]==jug)   cont++;
                else    b1=1;
            }
            if((c+i)<8 && b2==0){    //derecha
                if (t[f][(c+i)]==jug)  cont++;
                else    b2=1;
            }
        }
        return obtenerPuntaje(cont);
    }
 
/**              |                                *
 *      Arriba:  |                        Abajo:  | 
 *               |                                |
 *               *                                |
 */
    private int obtenerPuntajeVertical(int jug, int f, int c, int[][] t)
    {
        int cont = 0;
        int b1=0, b2=0;
      
        for (int i=1; i<4; i++){
            if ((f-i)>-1 && b1==0){     //arriba
                if (t[(f-i)][c]==jug)   cont++;
                else    b1=1;
            }
            if((f+i)<8 && b2==0){    //abajo
                if (t[(f+i)][c]==jug)  cont++;
                else    b2=1;
            }
        }
        return obtenerPuntaje(cont);
    }

/**
 * Permite obtener el numero adecuado de puntaje
 * @param nro: numero de entrada
 * @return el puntaje adecuado.
 */
    private int obtenerPuntaje(int nro){
        switch(nro){
            case 0: return 0;
            case 1: return 1;
            case 2: return 10;
            default: return -1;
        }
    }

/**
 * Aca se comparan los pesos mios y los de mi rival y se pueden presentar las sig situaciones:
 * Si los pesos maximos de ambos son los mismos, le damos prioridad a nuestro movimiento, en caso
 * contrario se comparan los dos y se le da prioridad al peso maximo
 * @return la prox movida
 */
    private int[] calcularProxMovimiento(){
        int[][] ptosMax=new int[2][3];
        for (int i = 0; i < 8; i++)
        {
            for (int j = 0; j < 8; j++)
            {
                if(misPuntos[i][j]>ptosMax[0][2]){
                    ptosMax[0][2]=misPuntos[i][j];  //guardo el puntaje nuestro
                    ptosMax[0][0]=i;                //guardo la fila
                    ptosMax[0][1]=j;                //guardo la columna
                }
                if(susPuntos[i][j]>ptosMax[1][2]){
                    ptosMax[1][2]=susPuntos[i][j];  //guardo el puntaje de el
                    ptosMax[1][0]=i;                //guardo la fila
                    ptosMax[1][1]=j;                //guardo la columna
                }
            }
        }
        if(priorizar==2){   //priorizo el ataque antes q la defensa
            int dif=ptosMax[0][2]-ptosMax[1][2];
            if(dif==0){
                casillero[0]=ptosMax[0][0];
                casillero[1]=ptosMax[0][1];
            }else{
                if(ptosMax[0][2]>ptosMax[1][2]){
                    casillero[0]=ptosMax[0][0];
                    casillero[1]=ptosMax[0][1];
                }else{
                    casillero[0]=ptosMax[1][0];
                    casillero[1]=ptosMax[1][1];
                }
            }
        }else{  //priorizo la defensa
            if(ptosMax[0][2]>ptosMax[1][2]){
                casillero[0]=ptosMax[0][0];
                casillero[1]=ptosMax[0][1];
            }else{
                casillero[0]=ptosMax[1][0];
                casillero[1]=ptosMax[1][1];
            }
        }
        return casillero;
    }


    private void verificarElementoTablero(int[][] t){
        for(int i=0; i<8; i++){
            for(int j=0; j<8; j++){
                if(t[i][j]==2)  priorizar=1;
            }
        }
        priorizar=2;
    }

    public String devolverNombre(){
        return "Cuatro en Raya";
    }

    public String devolverIntegrantes(){
        return "Giorda Cristian - Luna Martín - Liberal Juan - Sanchez Luciano";
    }

    public String devolverGrupo(){
        return "Grupo Nº ";
    }

    public String devolverCurso(){
        return "5k3";
    }
}
